package mylittleinvestigations;
import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.CaseInformation.Case;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import java.io.IOException;
import java.util.ArrayList;
import org.newdawn.slick.*;

public class Animation
{
    private String id;
    private ArrayList<Frame> frameList;
    private Frame curFrame;
    private int curFrameIndex;

    public Animation(String id)
    {
        this.id = id;
        this.frameList = new ArrayList<Frame>();
        this.curFrame = null;
        this.curFrameIndex = -1;
    }
    
    private String groupId;
    
    public String getGroupId() { return this.groupId; }
    public void setGroupId(String groupId) { this.groupId = groupId; }

    public void AddFrame(int msDuration, String textureId)
    {
        this.frameList.add(new Frame(msDuration, textureId));
    }

    public void AddHoofstep()
    {
        this.frameList.get(this.frameList.size() - 1).AddHoofstep();
    }

    public void Begin()
    {
        this.Reset();
        this.curFrame.Begin();
    }

    public void Update(GameContainer gc, int delta)
    {
        this.curFrame.Update(gc, delta);

        if (this.curFrame.getIsFinished())
        {
            double overflowDuration = this.curFrame.getOverflowDuration();
            this.curFrameIndex++;

            if (this.curFrameIndex == this.frameList.size())
            {
                this.curFrameIndex = 0;
            }

            this.curFrame = this.frameList.get(this.curFrameIndex);
            this.curFrame.Begin(overflowDuration);
        }
    }

    public void Draw(GameContainer gc, Graphics g, Vector2 position, boolean flipHorizontally, float scale)
    {
        this.curFrame.Draw(gc, g, position, flipHorizontally, scale);
    }

    public void Reset()
    {
        this.curFrameIndex = 0;
        this.curFrame = this.frameList.get(0);
    }

    public Animation Clone()
    {
        Animation cloneAnimation = new Animation(this.id);

        cloneAnimation.frameList = this.frameList;
        cloneAnimation.curFrame = this.curFrame;
        cloneAnimation.curFrameIndex = this.curFrameIndex;

        return cloneAnimation;
    }

    public void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("Animation");
        
        Case.getInstance().getSpriteManager().StartGroup(this.groupId != null ? this.groupId : this.id);
        
        for (int i = 0; i < this.frameList.size(); i++)
        {
            this.frameList.get(i).SaveToXml(writer);
        }
        
        Case.getInstance().getSpriteManager().EndGroup();
        
        writer.EndElement();
    }

    public Animation(CaseXmlReader reader)
    {
        this.frameList = new ArrayList<Frame>();
        this.curFrame = null;
        this.curFrameIndex = -1;
        
        reader.StartElement("Animation");
        
        reader.StartList("Frame");
        
        while (reader.MoveToNextListItem())
        {
            this.frameList.add(new Frame(reader));
        }
        
        reader.EndElement();
    }
    
    public void markChildSprites(String markParent)
    {
        for(Frame f : frameList)
        {
            f.markChildSprites(markParent);
        }
    }

    private class Frame
    {
        private int msDuration;
        private String textureId;
        private Sprite sprite;
        private Sound sound;

        private double elapsedDuration;

        private Sprite getSprite()
        {
            if (this.sprite == null)
            {
                this.sprite = Case.getInstance().getSpriteManager().GetSpriteFromId(this.textureId);
            }

            return this.sprite;
        }

        public double getOverflowDuration()
        {
            double overflowDuration = elapsedDuration - this.msDuration;

            if (overflowDuration > 0)
            {
                return overflowDuration;
            }
            else
            {
                return 0;
            }
        }

        public boolean getIsFinished()
        {
            return this.msDuration > 0 && this.elapsedDuration >= this.msDuration;
        }

        public Frame(int msDuration, String textureId)
        {
            this.msDuration = msDuration;
            this.textureId = textureId;
        }
        
        public void AddHoofstep()
        {
            this.sound = new HoofstepSound();
        }
        
        public void markChildSprites(String markParent)
        {
            this.getSprite().markChildSprites(markParent);
        }

        public void Begin()
        {
            this.elapsedDuration = 0;
        }

        public void Begin(double overflowDuration)
        {
            this.elapsedDuration = overflowDuration;
        }

        public void Update(GameContainer gc, int delta)
        {
            this.elapsedDuration += delta;
        }

        public void Draw(GameContainer gc, Graphics g, Vector2 position, boolean flipHorizontally, float scale)
        {
            this.getSprite().Draw(gc, g, position, Color.white, scale, flipHorizontally);
        }

        private void SaveToXml(CaseXmlWriter writer) throws IOException
        {
            writer.StartElement("Frame");
            writer.WriteIntElement("MsDuration", this.msDuration);
            writer.WriteSpriteId("SpriteId", this.textureId);
            
            if (this.sound != null)
            {
                writer.StartElement("Sound");
                this.sound.SaveToXml(writer);
                writer.EndElement();
            }
            
            writer.EndElement();
        }

        public Frame(CaseXmlReader reader)
        {
            this.msDuration = reader.ReadIntElement("MsDuration");
            this.textureId = reader.ReadTextElement("TextureId");
        }
        
        private abstract class Sound
        {
            public abstract void Play();
            public abstract void SaveToXml(CaseXmlWriter writer) throws IOException;
        }
        
        private class HoofstepSound extends Sound
        {
            public void Play()
            {
                
            }
            
            public void SaveToXml(CaseXmlWriter writer) throws IOException
            {
                writer.StartElement("HoofstepSound");
                writer.EndElement();
            }
        }
    }
}